
package com.hlkj.pay.app.merchant.ext.impl.kuaiqian.util;

import java.io.IOException;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bill99.crypto.processor.DefaultP7CryptoProcessor;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.impl.kuaiqian.dto.Bill99AppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.kuaiqian.dto.Bill99Header;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 示例代码 仅演示加解密方法的使用，实际使用中，请根据业务需求，自行实现
 */
@Service
@Slf4j
public class BuildHttpsClient {

    private static DefaultP7CryptoProcessor defaultP7CryptoProcessor;

    /*
     * @method function 请求快钱
     */
    public String requestKQ(Bill99Header header, Object requestData, String url, Bill99AppChannelParams bill99AppChannelParams) throws Exception {
        log.info("快钱配置:{}", JsonUtils.toJsonString(bill99AppChannelParams));
        // E:\work\local_file\secret\20241126
        /// www/wwwroot/pay/uploads/secret/20241126/
        if (defaultP7CryptoProcessor == null) {
            log.info("初始化快钱配置:{}", JsonUtils.toJsonString(bill99AppChannelParams));
            defaultP7CryptoProcessor = new DefaultP7CryptoProcessor(Bill99CertConfigLoader.loadConfig(bill99AppChannelParams));
            log.info("快钱配置完成");
        }

        log.info("快钱配置 defaultP7CryptoProcessor:{}", JSONUtil.toJsonStr(defaultP7CryptoProcessor));

        JSONObject jsonObject = (JSONObject) JSON.toJSON(header);
        JSONObject body = (JSONObject) JSON.toJSON(requestData);

        log.info("快钱配置 header:{},body:{}",jsonObject,body);
        /*
         * 对body明文进行加密+签名
         */
        JSONObject encryptBody;
        try {
            // 调用加密方法
            encryptBody = defaultP7CryptoProcessor.seal(body.toString());
        }
        catch (Exception e) {
            log.error("请求快钱，加密加签出错。", e);
            throw e;
        }
        /*
         * 生成商户请求快钱的密文
         */
        JSONObject requestString = new JSONObject();
        requestString.put("head", jsonObject);
        requestString.put("requestBody", encryptBody);
        log.info("商户请求快钱密文 = {}", requestString.toJSONString());
        // 环境指定：sandbox-快钱测试环境；prod-快钱生产环境
        log.info("请求快钱接口地址：{}", url);
        CloseableHttpClient httpClient;
        HttpPost httpPost = new HttpPost(url);
        // 如果https调用有配置ssl证书可以使用此方法获取：httpClient = BuildHttpsClient.defaultHttpClient ==
        // null ? createHttpsClient() : BuildHttpsClient.defaultHttpClient;
        httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(10000).build();
        httpPost.setConfig(requestConfig);
        httpPost.setEntity(new StringEntity(requestString.toJSONString(), Consts.UTF_8));
        String resp = httpClient.execute(httpPost, new ResponseHandler<String>() {

            @Override
            public String handleResponse(HttpResponse httpresponse) throws ClientProtocolException, IOException {
                int statusCode = httpresponse.getStatusLine().getStatusCode();
                log.info("99bill-response-statusCode = {}", statusCode);
                if (200 != statusCode) {
                    log.error("与快钱通信异常，业务状态未知，请查询确认！http-status-Code = {}", statusCode);
                    return null;
                }
                else {
                    String entityStr = "";
                    HttpEntity entity = httpresponse.getEntity();
                    if (null != entity) {
                        entityStr = EntityUtils.toString(entity, Consts.UTF_8);
                        log.info("快钱返回原始信息 = {}", entityStr);
                        JSONObject respEncryptObject = JSONObject.parseObject(entityStr);
                        JSONObject respHead = respEncryptObject.getJSONObject("head");
                        JSONObject respEncryptBody = respEncryptObject.getJSONObject("responseBody");

                        JSONObject respDecryptObject = new JSONObject();
                        String respSignedData = respEncryptBody.getString("signedData");
                        String respEnvelopedData = respEncryptBody.getString("envelopedData");
                        respDecryptObject.put("head", respHead);
                        if ("0000".equals(respHead.getString("responseCode"))) {
                            String respDecryptBody = null;
                            try {
                                respDecryptBody = defaultP7CryptoProcessor.unSeal(respEnvelopedData, respSignedData);
                            }
                            catch (Exception e) {
                                e.printStackTrace();
                                log.error("解密快钱响应时出现异常:", e);
                                return null;
                            }
                            respDecryptObject.put("responseBody", JSON.parse(respDecryptBody));
                            return respDecryptObject.toJSONString();
                            // if (!StringUtils.hasText(respDecryptBody)) {
                            // log.info("快钱返回明文信息 = {}", respDecryptObject.toJSONString());
                            // }
                            // else {
                            // log.error("快钱返回报文解密验签失败，请检查报错情况！");
                            // return null;
                            // }
                        }
                        else {
                            log.error("请求快钱出错, head报错信息 = {}", respHead.toJSONString());
                            return respDecryptObject.toJSONString();
                        }
                    }
                    else {
                        log.error("快钱返回内容为空，业务状态未知，请查询确认！");
                        return null;
                    }
                }
            }
        });
        return resp;
    }

    /**
     * 回调数据解密
     * 
     * @param bill99AppChannelParams
     * @param entityStr
     * @return
     * @throws Exception
     */
    public String unSeal(Bill99AppChannelParams bill99AppChannelParams, String entityStr) throws Exception {
        if (defaultP7CryptoProcessor == null) {
            defaultP7CryptoProcessor = new DefaultP7CryptoProcessor(Bill99CertConfigLoader.loadConfig(bill99AppChannelParams));
        }
        log.info("快钱解密原始信息 = {}", entityStr);
        JSONObject respEncryptObject = JSONObject.parseObject(entityStr);
        JSONObject respHead = respEncryptObject.getJSONObject("head");
        JSONObject respEncryptBody = respEncryptObject.getJSONObject("responseBody");
        if (respEncryptBody == null) {
            respEncryptBody = respEncryptObject.getJSONObject("requestBody");
        }

        JSONObject respDecryptObject = new JSONObject();
        String respSignedData = respEncryptBody.getString("signedData");
        String respEnvelopedData = respEncryptBody.getString("envelopedData");
        respDecryptObject.put("head", respHead);
        String respDecryptBody = null;
        try {
            respDecryptBody = defaultP7CryptoProcessor.unSeal(respEnvelopedData, respSignedData);
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("解密快钱响应时出现异常:", e);
            return null;
        }
        respDecryptObject.put("responseBody", JSON.parse(respDecryptBody));
        return respDecryptObject.toJSONString();
    }

    /**
     * 返回数据加密
     * 
     * @param header
     * @param requestData
     * @param bill99AppChannelParams
     * @param entityStr
     * @return
     * @throws Exception
     */
    public String seal(Bill99Header header, Object requestData, Bill99AppChannelParams bill99AppChannelParams) throws Exception {
        if (defaultP7CryptoProcessor == null) {
            defaultP7CryptoProcessor = new DefaultP7CryptoProcessor(Bill99CertConfigLoader.loadConfig(bill99AppChannelParams));
        }
        JSONObject jsonObject = (JSONObject) JSON.toJSON(header);
        JSONObject body = (JSONObject) JSON.toJSON(requestData);
        /*
         * 对body明文进行加密+签名
         */
        JSONObject encryptBody;
        try {
            // 调用加密方法
            encryptBody = defaultP7CryptoProcessor.seal(body.toString());
        }
        catch (Exception e) {
            log.error("请求快钱，加密加签出错。", e);
            throw e;
        }
        /*
         * 生成商户请求快钱的密文
         */
        JSONObject requestString = new JSONObject();
        requestString.put("head", jsonObject);
        requestString.put("requestBody", encryptBody);
        log.info("商户请求快钱密文 = {}", requestString.toJSONString());
        return requestString.toJSONString();
    }
}
